
<!DOCTYPE HTML>
<html>
<head>
	<meta charset="utf-8">
	<title>编写一个iOS越狱插件(tweak) - 乐の博客</title>
	<meta name="author" content="zhidong">

	
	<meta name="description" content="编写一个iOS越狱插件(tweak) 折腾了几天，搞定一个tweak(FPSCounter)，把一些重要步骤记录一下。 关于这个插件 这是个帧速计数器(FPSCounter)，方便我们查看应用的帧速，从而做出相应优化。这里不仅可以看自己的应用，也可以看系统中其他应用。 截图： 如何安装 &hellip;">
	<meta name="keywords" content="iOS,tweak,jailbreak,FPSCounter">

  <!-- http://t.co/dKP3o1e -->
  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1">

	<link href="/atom.xml" rel="alternate" title="乐の博客" type="application/atom+xml">
	
	<link rel="canonical" href="https://zhidong.rochu.cn/blog/2016/02/04/write-a-tweak/">
	<link href="/favicon.png" rel="shortcut icon">
	<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
	<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
	<script src="/javascripts/libs/jquery.min.js"></script>
	<!-- <link href='//fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'> -->
	
</head>


<body>
	<div class="container">
		<div class="left-col">
			<div class="intrude-less">
			<header id="header" class="inner"><div class="profilepic">	
	<script src="/javascripts/md5.js"></script>
	<script type="text/javascript">
		document.write("<img src='/images/pingtouge.png' alt='Profile Picture' style='width: 160px;' />");
	</script>
</div>
<h1><a href="/">乐の博客</a></h1>
<p class="subtitle">行而不思则罔，思而不行则怠</p>
<nav id="main-nav"><ul>
	<li><a href="/">Blog</a></li>
	<li><a href="/about">About</a></li>
	<li><a href="/portfolio">Portfolio</a></li>
	<li><a href="/archives">Archive</a></li>
</ul>
</nav>
<nav id="sub-nav">
	<div class="social">
		
		<a class="weibo" href="http://www.weibo.com/agdsdl" title="Weibo">Weibo</a>
		
		
		
		
		
		<a class="github" href="https://github.com/agdsdl" title="GitHub">GitHub</a>
		
		
		
		
		
		
		
		<a class="rss" href="/atom.xml" title="RSS">RSS</a>
		
	</div>
</nav>
<p class="description">知冬的后花园</p>
</header>				
			</div>
		</div>	
		<div class="mid-col">
			
				
			
			<div class="mid-col-container">
				<div id="content" class="inner"><article class="post" itemscope itemtype="http://schema.org/BlogPosting">
	<h1 class="title" itemprop="name">编写一个iOS越狱插件(tweak)</h1>
	<div class="entry-content" itemprop="articleBody"><p>折腾了几天，搞定一个tweak(FPSCounter)，把一些重要步骤记录一下。</p>

<h2>关于这个插件</h2>

<p>这是个帧速计数器(FPSCounter)，方便我们查看应用的帧速，从而做出相应优化。这里不仅可以看自己的应用，也可以看系统中其他应用。</p>

<h3>截图：</h3>

<p><img src="https://github.com/agdsdl/fpscounter/blob/master/images/preview1.jpg?raw=true" alt="preview1" />
<img src="https://github.com/agdsdl/fpscounter/blob/master/images/preview2.jpg?raw=true" alt="preview2" /></p>

<h3>如何安装</h3>

<ul>
<li>在Cydia中搜索<code>FPSCounter</code>.(你的Cydia中必须有BigBoss源)</li>
<li>或者到<a href="https://github.com/agdsdl/fpscounter">source code</a>下载后自行编译安装。</li>
</ul>


<h2>前提条件</h2>

<p>一个越狱的iOS设备。</p>

<p>需要越狱的设备来获取可用的CydiaSubstrate, 同时也需要越狱设备来安装和测试。</p>

<h2>安装和配置Theos</h2>

<p><a href="https://github.com/DHowett/theos.git">Theos</a>大大简化了tweak的编写，建议大家从Theos开始编写tweak。</p>

<p>按照<a href="http://iosre.com/">《iOS应用逆向工程》</a>中所述，将Theos<a href="https://github.com/DHowett/theos.git">下载</a>下来之后，还有一系列的配置。</p>

<p>我将这些配置工作写成了一个<a href="https://github.com/agdsdl/dotfiles/blob/master/init/82_jailbreak_tools.sh">脚本</a>,省去每次都做这些繁琐的配置。</p>

<p>这个脚本默认Theos是下载到“个人目录/jailbreak/Opensource”，如果不想修改脚本，可用使用与脚本相同的目录。</p>

<h2>配置默认路径</h2>

<p>修改.bash_profile文件，将~/jailbreak/Opensource/theos/bin加入到PATH中。</p>

<p>保存之后重新启动一下终端。</p>

<h2>获取iOS系统头文件</h2>

<p>按照<a href="http://iosre.com/">《iOS应用逆向工程》</a>的介绍，正规的获取方式是用dyld_decache从iOS设备中/System/Library/Caches/com.apple.dyld/dyld_shared_cache_armXX将二进制文件提取出来，然后用class-dump去把头文件提取出来。</p>

<p>为了方便起见，这里采用第二种方法，就是直接用<a href="https://github.com/rpetrich/iphoneheaders.git">rpetrich的头文件</a>。</p>

<p>将这些头文件放到Theos的include目录下。</p>

<p>开始编写tweak！</p>

<!-- more -->


<h2>新建一个tweak</h2>

<p>在终端运行nic.pl, 在出现的菜单中选择想要的tweak种类。</p>

<p>一般的tweak是选tweak类型。preference_bundle是可自定义的设置插件，如果你选择这种，会遇到一些奇怪的坑，下面会给出解决办法：）</p>

<p>普通的tweak会包含以下文件：</p>

<ul>
<li>control 包含deb包管理的基本信息</li>
<li>tweak.x 插件源文件，支持c， objectiveC，<a href="http://iphonedevwiki.net/index.php/Logos">Logos语法</a></li>
<li>XXX.plist 指明插件在哪些应用中加载</li>
<li>layout目录 相当于iOS设备根目录，里面的文件会被对应的安装到设备的对应位置。</li>
<li>Makefile make文件</li>
</ul>


<h2>修改make文件</h2>

<p>在Makefile最上面加上这两句：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='Makefile'><span class='line'><span class="k">export </span><span class="nv">ARCHS</span> <span class="o">=</span> armv7 armv7s arm64
</span><span class='line'><span class="k">export </span><span class="nv">TARGET</span> <span class="o">=</span> iphone:clang:latest:7.0
</span></code></pre></td></tr></table></div></figure>


<p>上面一句表示要编译armv7 armv7s arm64三种cpu架构，</p>

<p>下面一句表示编译iPhone插件：用clang编译：用系统中最新SDK编译：目标系统是7.0（和以上）</p>

<h2>编译</h2>

<p>在终端输入：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>make
</span></code></pre></td></tr></table></div></figure>


<p>编译成功后，输入</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>make package install
</span></code></pre></td></tr></table></div></figure>


<p>一条命令完成编译打包和安装。</p>

<p>如果有错误，请参考下面的问题。</p>

<h2>遇到的问题</h2>

<ul>
<li><p>报错找不到IOSurfaceAPI.h。解决办法：rpetrich头文件包里有这个文件，手动拷贝到include目录。</p></li>
<li><p>编译错误，报错architecture not supported。解决办法：如果是报错在.m文件或.mm文件，Theos对.m的支持不好，将其后缀改为.x文件或.xm文件一般就可以解决。</p></li>
<li><p>link错误，Undefined symbols。解决办法：Makefile中有XXX_FRAMEWORKS = UIKit，在这后面把你用到的framework都加上。</p>

<p>如果还用了其他的库，需要在Makefile中加上XXX_LDFLAGS = -lx，这里x是变量，代指库名。</p></li>
<li><p>make package install时报错：make install requires that you set THEOS_DEVICE_IP in your environment. It is also recommended that you have public-key authentication set up for root over SSH, or you will be entering your password a lot.</p>

<p>需运行<code>export THEOS_DEVICE_IP=你手机的ip地址</code>。</p>

<p>后面那句话是建议你把电脑ssh 公钥设为手机的authorized_keys，这样就不用每次输密码了。</p></li>
<li><p>在设备上插件不运行。解决办法：连上xcode看device log，是否是cpu type不支持或者其他原因。</p></li>
<li><p>如果还有问题，请仔细看编译警告、device log，并自己打log，直到确定问题所在。</p></li>
<li><p>tweak默认是mrc的，一定要正确保持和释放。这里不太建议改成ARC，除非<a href="http://iphonedevwiki.net/index.php/Using_ARC_in_tweaks">你知道你在干嘛</a>。</p></li>
</ul>


<h2>学习和模仿</h2>

<p>成长离不开学习和模仿，有以下途径可以模仿：</p>

<ul>
<li>在手机上用cydia查看已安装的tweak，看他们有哪些文件，然后用iFunbox将这些文件拷贝出来学习或逆向。</li>
<li>github上有大量开源的代码（比如大神rpetrich、DHowett等），可以看看别人是怎么写的。</li>
</ul>


<h2>参考</h2>

<p><a href="http://iphonedevwiki.net/index.php/Main_Page">http://iphonedevwiki.net/index.php/Main_Page</a></p>

<p><a href="https://www.andyibanez.com/creating-aggregate-projects-theos-configurable-tweak/">https://www.andyibanez.com/creating-aggregate-projects-theos-configurable-tweak/</a></p>

<p><a href="https://github.com/mlnlover11/TouchIDEverywhere/issues/2">https://github.com/mlnlover11/TouchIDEverywhere/issues/2</a></p>

<p><a href="https://github.com/DHowett/theos/issues/73">https://github.com/DHowett/theos/issues/73</a></p>

<p><a href="http://bbs.iosre.com/t/theos-make-error-unsupported-architecture/1196">http://bbs.iosre.com/t/theos-make-error-unsupported-architecture/1196</a></p>
</div>

</article>
<!-- 
	<div class="share">
	<div class="addthis_toolbox addthis_default_style addthis_16x16_style">
	
	
	
	
	
	<a class="addthis_button_compact"></a>
	<a class="addthis_counter addthis_bubble_style"></a>
	</div>
  <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid="></script>
</div>

 -->


<section id="comment">
    <h1 class="title">Comments</h1>
    <div id="gitalk-container"></div>
    <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
    <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
    <script>
    const gitalk = new Gitalk({
    clientID: '29bbf743e30b99394771',
    clientSecret: '41e4b7f1aa79742fc459f2971ad51596df5e4dda',
    repo: 'agdsdl.github.io',
    owner: 'agdsdl',
    admin: ['agdsdl'],
    id: location.pathname,      // Ensure uniqueness and length less than 50
    distractionFreeMode: false  // Facebook-like distraction free mode
    })

    gitalk.render('gitalk-container')
    </script>
</section></div>
			</div>
			<footer id="footer" class="inner">Copyright &copy; 2019

    zhidong

<br>
Powered by Octopress.

Design credit: <a href="http://shashankmehta.in/archive/2012/greyshade.html">Shashank Mehta</a></footer>
			<script src="/javascripts/slash.js"></script>
<!-- <script src="/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
	$('.fancybox').fancybox();
})(jQuery);
</script> Delete or comment this line to disable Fancybox -->




	<script type="text/javascript">
		var _gaq = _gaq || [];
		_gaq.push(['_setAccount', 'UA-65560025-1']);
		_gaq.push(['_trackPageview']);

		(function() {
			var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
			ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
			var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
		})();
	</script>



		</div>
	</div>
</body>
</html>
